'use client';

import React, { useState, useEffect, useRef, useCallback, ReactNode, CSSProperties } from 'react';

export interface VirtualListProps<T> {
  // 数据项数组
  items: T[];
  // 渲染单个项的函数
  renderItem: (item: T, index: number, style: CSSProperties) => ReactNode;
  // 项高度（固定高度或计算函数）
  itemHeight: number | ((item: T, index: number) => number);
  // 容器高度
  height: number | string;
  // 容器宽度
  width?: number | string;
  // 预渲染的屏幕数量
  overscan?: number;
  // 滚动位置变化回调
  onScroll?: (scrollTop: number, scrollDirection: 'forward' | 'backward') => void;
  // 初始滚动位置
  initialScrollTop?: number;
  // 滚动到指定索引
  scrollToIndex?: number;
  // 容器类名
  className?: string;
  // 项容器类名
  itemClassName?: string;
}

/**
 * 虚拟列表组件
 * 
 * 高效渲染大型列表，只渲染可见区域的项
 * 
 * @example
 * ```tsx
 * <VirtualList
 *   items={items}
 *   renderItem={(item, index, style) => (
 *     <div style={style}>{item.name}</div>
 *   )}
 *   itemHeight={50}
 *   height={400}
 * />
 * ```
 */
export function VirtualList<T>({
  items,
  renderItem,
  itemHeight,
  height,
  width = '100%',
  overscan = 3,
  onScroll,
  initialScrollTop = 0,
  scrollToIndex,
  className = '',
  itemClassName = ''
}: VirtualListProps<T>) {
  // 容器引用
  const containerRef = useRef<HTMLDivElement>(null);
  // 上次滚动位置
  const lastScrollTopRef = useRef<number>(initialScrollTop);
  // 上次滚动方向
  const lastScrollDirectionRef = useRef<'forward' | 'backward'>('forward');
  // 滚动位置
  const [scrollTop, setScrollTop] = useState<number>(initialScrollTop);
  
  // 获取项高度
  const getItemHeight = useCallback(
    (index: number): number => {
      if (typeof itemHeight === 'function') {
        return itemHeight(items[index], index);
      }
      return itemHeight;
    },
    [itemHeight, items]
  );
  
  // 计算项位置和高度
  const getItemMetadata = useCallback(
    (index: number) => {
      let offset = 0;
      
      for (let i = 0; i < index; i++) {
        offset += getItemHeight(i);
      }
      
      return {
        offset,
        height: getItemHeight(index)
      };
    },
    [getItemHeight]
  );
  
  // 计算总高度
  const estimateTotalHeight = useCallback(() => {
    return items.reduce((total, _, index) => total + getItemHeight(index), 0);
  }, [items, getItemHeight]);
  
  // 计算可见范围
  const getVisibleRange = useCallback(
    (scrollOffset: number, containerHeight: number) => {
      let startIndex = 0;
      let stopIndex = 0;
      
      // 找到第一个可见项
      let offset = 0;
      for (let i = 0; i < items.length; i++) {
        const height = getItemHeight(i);
        if (offset + height > scrollOffset) {
          startIndex = i;
          break;
        }
        offset += height;
      }
      
      // 找到最后一个可见项
      for (let i = startIndex; i < items.length; i++) {
        const height = getItemHeight(i);
        if (offset >= scrollOffset + containerHeight) {
          stopIndex = i - 1;
          break;
        }
        offset += height;
        stopIndex = i;
      }
      
      // 应用overscan
      startIndex = Math.max(0, startIndex - overscan);
      stopIndex = Math.min(items.length - 1, stopIndex + overscan);
      
      return { startIndex, stopIndex };
    },
    [items, getItemHeight, overscan]
  );
  
  // 处理滚动事件
  const handleScroll = useCallback(
    (event: React.UIEvent<HTMLDivElement>) => {
      const { scrollTop: currentScrollTop } = event.currentTarget;
      const scrollDirection = currentScrollTop > lastScrollTopRef.current ? 'forward' : 'backward';
      
      lastScrollTopRef.current = currentScrollTop;
      lastScrollDirectionRef.current = scrollDirection;
      
      setScrollTop(currentScrollTop);
      
      if (onScroll) {
        onScroll(currentScrollTop, scrollDirection);
      }
    },
    [onScroll]
  );
  
  // 滚动到指定索引
  useEffect(() => {
    if (scrollToIndex !== undefined && containerRef.current) {
      const { offset } = getItemMetadata(scrollToIndex);
      containerRef.current.scrollTop = offset;
    }
  }, [scrollToIndex, getItemMetadata]);
  
  // 设置初始滚动位置
  useEffect(() => {
    if (containerRef.current && initialScrollTop > 0) {
      containerRef.current.scrollTop = initialScrollTop;
    }
  }, [initialScrollTop]);
  
  // 计算容器高度
  const containerHeight = typeof height === 'number' ? `${height}px` : height;
  
  // 计算总高度
  const totalHeight = estimateTotalHeight();
  
  // 获取可见范围
  const containerHeight_num = typeof height === 'number' ? height : 
    containerRef.current ? containerRef.current.clientHeight : 0;
  const { startIndex, stopIndex } = getVisibleRange(scrollTop, containerHeight_num);
  
  // 渲染可见项
  const visibleItems: ReactNode[] = [];
  for (let i = startIndex; i <= stopIndex && i < items.length; i++) {
    const { offset, height } = getItemMetadata(i);
    
    const style: CSSProperties = {
      position: 'absolute',
      top: 0,
      left: 0,
      width: '100%',
      height: `${height}px`,
      transform: `translateY(${offset}px)`
    };
    
    visibleItems.push(
      <div key={i} className={itemClassName} style={{ height, position: 'relative' }}>
        {renderItem(items[i], i, style)}
      </div>
    );
  }
  
  return (
    <div
      ref={containerRef}
      className={`virtual-list-container ${className}`}
      style={{
        height: containerHeight,
        width,
        overflow: 'auto',
        position: 'relative'
      }}
      onScroll={handleScroll}
    >
      <div
        className="virtual-list-inner"
        style={{
          height: `${totalHeight}px`,
          position: 'relative'
        }}
      >
        {visibleItems}
      </div>
    </div>
  );
} 